home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Dev / gcc263-src.lha / gcc-2.6.3 / config / clipper / clipper.c next >
C/C++ Source or Header  |  1993-07-09  |  11KB  |  474 lines

  1. /* Subroutines for insn-output.c for Clipper
  2.    Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
  3.  
  4.    Contributed by Holger Teutsch (holger@hotbso.rhein-main.de)
  5.  
  6. This file is part of GNU CC.
  7.  
  8. GNU CC is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2, or (at your option)
  11. any later version.
  12.  
  13. GNU CC is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with GNU CC; see the file COPYING.  If not, write to
  20. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. #include <stdio.h>
  23. #include "config.h"
  24. #include "rtl.h"
  25. #include "regs.h"
  26. #include "hard-reg-set.h"
  27. #include "real.h"
  28. #include "insn-config.h"
  29. #include "conditions.h"
  30. #include "insn-flags.h"
  31. #include "output.h"
  32. #include "insn-attr.h"
  33. #include "tree.h"
  34. #include "c-tree.h"
  35. #include "expr.h"
  36. #include "flags.h"
  37. #include "machmode.h"
  38.  
  39. extern char regs_ever_live[];
  40.  
  41. extern int frame_pointer_needed;
  42.  
  43. static int frame_size;
  44.  
  45. /*
  46.  * compute size of a clipper stack frame where 'lsize' is the required
  47.  * space for local variables.
  48.  */
  49.  
  50. int
  51. clipper_frame_size (lsize)
  52.      int lsize;
  53. {
  54.   int i,size;                /* total size of frame */
  55.   int save_size;
  56.   save_size = 0;            /* compute size for reg saves */
  57.  
  58.   for (i = 16; i < 32; i++)
  59.     if (regs_ever_live[i] && !call_used_regs[i])
  60.       save_size += 8;
  61.  
  62.   for (i = 0; i < 16; i++)
  63.     if (regs_ever_live[i] && !call_used_regs[i])
  64.       save_size += 4;
  65.  
  66.   size = lsize + save_size;
  67.  
  68.   size = (size + 7) & ~7;        /* align to 64 Bit */
  69.   return size;
  70. }
  71.  
  72. /*
  73.  * prologue and epilogue output
  74.  * function is entered with pc pushed, i.e. stack is 32 bit aligned
  75.  *
  76.  * current_function_args_size == 0 means that the current function's args
  77.  * are passed totally in registers i.e fp is not used as ap.
  78.  * If frame_size is also 0 the current function does not push anything and
  79.  * can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit
  80.  * can be omitted.
  81.  *
  82.  */
  83. void
  84. output_function_prologue (file, lsize)
  85.      FILE *file;
  86.      int lsize;                /* size for locals */
  87. {
  88.   int i, offset;
  89.   int size;
  90.  
  91.   frame_size = size = clipper_frame_size (lsize);
  92.  
  93.   if (frame_pointer_needed)
  94.     {
  95.       fputs ("\tpushw  fp,sp\n", file);
  96.       fputs ("\tmovw   sp,fp\n", file);
  97.     }
  98.   else if (size != 0 || current_function_args_size != 0)
  99.     {
  100.       size += 4;            /* keep stack aligned */
  101.       frame_size = size;        /* must push data or access args */
  102.     }
  103.  
  104.   if (size)
  105.     {
  106.       if (size < 16)
  107.     fprintf (file, "\tsubq   $%d,sp\n", size);
  108.       else
  109.     fprintf (file, "\tsubi   $%d,sp\n", size);
  110.  
  111.       /* register save slots are relative to sp, because we have small positive
  112.      displacements and this works whether we have a frame pointer or not */
  113.  
  114.       offset = 0;
  115.       for (i = 16; i < 32; i++)
  116.     if (regs_ever_live[i] && !call_used_regs[i])
  117.       {
  118.         if (offset == 0)
  119.           fprintf (file, "\tstord  f%d,(sp)\n", i-16);
  120.         else
  121.           fprintf (file, "\tstord  f%d,%d(sp)\n", i-16, offset);
  122.         offset += 8;
  123.       }
  124.  
  125.       for (i = 0; i < 16; i++)
  126.     if (regs_ever_live[i] && !call_used_regs[i])
  127.       {
  128.         if (offset == 0)
  129.           fprintf (file, "\tstorw  r%d,(sp)\n", i);
  130.         else
  131.           fprintf (file, "\tstorw  r%d,%d(sp)\n", i, offset);
  132.         offset += 4;
  133.       }
  134.     }
  135. }
  136.  
  137. void
  138. output_function_epilogue (file, size)
  139.      FILE *file;
  140.      int size;                /* ignored */
  141. {
  142.   int i, offset;
  143.  
  144.   if (frame_pointer_needed)
  145.     {
  146.       offset = -frame_size;
  147.  
  148.       for (i = 16; i < 32; i++)
  149.     if (regs_ever_live[i] && !call_used_regs[i])
  150.       {
  151.         fprintf (file, "\tloadd  %d(fp),f%d\n", offset, i-16);
  152.         offset += 8;
  153.       }
  154.  
  155.       for (i = 0; i < 16; i++)
  156.     if (regs_ever_live[i] && !call_used_regs[i])
  157.       {
  158.         fprintf (file, "\tloadw  %d(fp),r%d\n", offset, i);
  159.         offset += 4;
  160.       }
  161.  
  162.       fputs ("\tmovw   fp,sp\n\tpopw   sp,fp\n\tret    sp\n",
  163.          file);
  164.     }
  165.  
  166.   else                    /* no frame pointer */
  167.     {
  168.       offset = 0;
  169.  
  170.       for (i = 16; i < 32; i++)
  171.     if (regs_ever_live[i] && !call_used_regs[i])
  172.       {
  173.         if (offset == 0)
  174.           fprintf (file, "\tloadd  (sp),f%d\n", i-16);
  175.         else
  176.           fprintf (file, "\tloadd  %d(sp),f%d\n", offset, i-16);
  177.         offset += 8;
  178.       }
  179.  
  180.       for (i = 0; i < 16; i++)
  181.     if (regs_ever_live[i] && !call_used_regs[i])
  182.       {
  183.         if (offset == 0)
  184.           fprintf (file, "\tloadw  (sp),r%d\n", i);
  185.         else
  186.           fprintf (file, "\tloadw  %d(sp),r%d\n", offset, i);
  187.         offset += 4;
  188.       }
  189.  
  190.       if (frame_size > 0)
  191.     {
  192.       if (frame_size < 16)
  193.         fprintf (file, "\taddq   $%d,sp\n", frame_size);
  194.       else
  195.         fprintf (file, "\taddi   $%d,sp\n", frame_size);
  196.     }
  197.  
  198.       fputs ("\tret    sp\n", file);
  199.     }
  200. }
  201.  
  202. /*
  203.  * blockmove
  204.  *
  205.  * clipper_movstr ()
  206.  */
  207. void
  208. clipper_movstr (operands)
  209.      rtx *operands;
  210. {
  211.   rtx dst,src,cnt,tmp,top,bottom,xops[3];
  212.   int align;
  213.   int fixed;
  214.  
  215.   extern FILE *asm_out_file;
  216.  
  217.   dst = operands[0];
  218.   src = operands[1];
  219.   /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */
  220.   align = INTVAL (operands[3]);
  221.   tmp = operands[4];
  222.   cnt = operands[5];
  223.  
  224.   if (GET_CODE (operands[2]) == CONST_INT) /* fixed size move */
  225.     {
  226.       if ((fixed = INTVAL (operands[2])) <= 0)
  227.     abort ();
  228.  
  229.       if (fixed <16)
  230.     output_asm_insn ("loadq  %2,%5", operands);
  231.       else
  232.     output_asm_insn ("loadi  %2,%5", operands);
  233.     }
  234.   else
  235.     {
  236.       fixed = 0;
  237.       bottom = (rtx)gen_label_rtx ();    /* need a bottom label */
  238.       xops[0] = cnt; xops[1] = bottom;
  239.       output_asm_insn ("movw   %2,%5", operands); /* count is scratch reg 5 */
  240.       output_asm_insn ("brle   %l1", xops);
  241.     }
  242.  
  243.  
  244.   top = (rtx)gen_label_rtx ();        /* top of loop label */
  245.   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (top));
  246.  
  247.  
  248.   xops[0] = src; xops[1] = tmp; xops[2] = dst;
  249.  
  250.   if (fixed && (align & 0x3) == 0)    /* word aligned move with known size */
  251.     {
  252.       if (fixed >= 4)
  253.     {
  254.       rtx xops1[2];
  255.       output_asm_insn(
  256.         "loadw  %a0,%1\n\taddq   $4,%0\n\tstorw  %1,%a2\n\taddq   $4,%2",
  257.               xops);
  258.  
  259.       xops1[0] = cnt; xops1[1] = top;
  260.       output_asm_insn ("subq   $4,%0\n\tbrgt   %l1", xops1);
  261.     }
  262.  
  263.       if (fixed & 0x2)
  264.     {
  265.       output_asm_insn ("loadh  %a0,%1\n\tstorh  %1,%a2", xops);
  266.       if (fixed & 0x1)
  267.         output_asm_insn ("loadb  2%a0,%1\n\tstorb  %1,2%a2", xops);
  268.     }
  269.       else
  270.     if (fixed & 0x1)
  271.       output_asm_insn ("loadb  %a0,%1\n\tstorb  %1,%a2", xops);
  272.     }
  273.   else
  274.     {
  275.       output_asm_insn(
  276.       "loadb  %a0,%1\n\taddq   $1,%0\n\tstorb  %1,%a2\n\taddq   $1,%2",
  277.               xops);
  278.  
  279.       xops[0] = cnt; xops[1] = top;
  280.       output_asm_insn ("subq   $1,%0\n\tbrgt   %l1", xops);
  281.     }
  282.  
  283.   if (fixed == 0)
  284.     ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (bottom));
  285. }
  286.  
  287.  
  288. print_operand_address (file, addr)
  289.      FILE *file;
  290.      register rtx addr;
  291. {
  292.   rtx op0,op1;
  293.  
  294.  retry:
  295.   switch (GET_CODE (addr))
  296.     {
  297.     case REG:
  298.       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
  299.       break;
  300.  
  301.     case PLUS:
  302.       /* can be 'symbol + reg' or 'reg + reg' */
  303.  
  304.       op0 = XEXP (addr, 0);
  305.       op1 = XEXP (addr, 1);
  306.  
  307.       if (GET_CODE (op0) == REG && GET_CODE (op1) == REG)
  308.     {
  309.       fprintf (file, "[%s](%s)",
  310.            reg_names[REGNO (op0)], reg_names[REGNO (op1)]);
  311.       break;
  312.     }
  313.  
  314.       if (GET_CODE (op0) == REG && CONSTANT_ADDRESS_P (op1))
  315.     {
  316.       output_addr_const (file, op1);
  317.       fprintf (file, "(%s)", reg_names[REGNO (op0)]);
  318.       break;
  319.     }
  320.  
  321.       if (GET_CODE (op1) == REG && CONSTANT_ADDRESS_P (op0))
  322.     {
  323.       output_addr_const (file, op0);
  324.       fprintf (file, "(%s)", reg_names[REGNO (op1)]);
  325.       break;
  326.     }
  327.       abort ();                /* Oh no */
  328.  
  329.     default:
  330.       output_addr_const (file, addr);
  331.     }
  332. }
  333.  
  334.  
  335. char *
  336. rev_cond_name (op)
  337.      rtx op;
  338. {
  339.   switch (GET_CODE (op))
  340.     {
  341.     case EQ:
  342.       return "ne";
  343.     case NE:
  344.       return "eq";
  345.     case LT:
  346.       return "ge";
  347.     case LE:
  348.       return "gt";
  349.     case GT:
  350.       return "le";
  351.     case GE:
  352.       return "lt";
  353.     case LTU:
  354.       return "geu";
  355.     case LEU:
  356.       return "gtu";
  357.     case GTU:
  358.       return "leu";
  359.     case GEU:
  360.       return "ltu";
  361.  
  362.     default:
  363.       abort ();
  364.     }
  365. }
  366.  
  367.  
  368. /* Do what is necessary for `va_start'.  The argument is ignored;
  369.    We fill in an initial va_list.  A pointer to this constructor
  370.    is returned. */
  371.  
  372.  
  373. struct rtx_def *
  374. clipper_builtin_saveregs (arglist)
  375.      tree arglist;
  376. {
  377.   extern int current_function_varargs;
  378.   rtx block, addr, argsize, scratch, r0_addr,r1_addr,f0_addr,f1_addr;
  379.  
  380.   /* Allocate the va_list constructor + save area for r0,r1,f0,f1 */
  381.  
  382.   block = assign_stack_local (BLKmode,
  383.                   (6 + 6) * UNITS_PER_WORD, 2 * BITS_PER_WORD);
  384.  
  385.   RTX_UNCHANGING_P (block) = 1;
  386.   RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
  387.  
  388.   addr = copy_to_reg (XEXP (block, 0));
  389.  
  390.   f0_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 24));
  391.   f1_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 32));
  392.   r0_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 40));
  393.   r1_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 44));
  394.  
  395.  
  396.   /* Store float regs  */
  397.  
  398.   emit_move_insn (gen_rtx (MEM, DFmode, f0_addr), gen_rtx (REG, DFmode, 16));
  399.   emit_move_insn (gen_rtx (MEM, DFmode, f1_addr), gen_rtx (REG, DFmode, 17));
  400.  
  401.   /* Store int regs  */
  402.  
  403.   emit_move_insn (gen_rtx (MEM, SImode, r0_addr), gen_rtx (REG, SImode, 0));
  404.   emit_move_insn (gen_rtx (MEM, SImode, r1_addr), gen_rtx (REG, SImode, 1));
  405.  
  406.   /* Store the arg pointer in the __va_stk member.  */
  407.  
  408.   emit_move_insn (gen_rtx (MEM, SImode, addr),
  409.           copy_to_reg (virtual_incoming_args_rtx));
  410.           
  411.  
  412.   /* now move addresses of the saved regs into the pointer array */
  413.  
  414.   scratch = gen_reg_rtx (Pmode);
  415.  
  416.   emit_move_insn (scratch, r0_addr);
  417.   emit_move_insn (gen_rtx (MEM, SImode,
  418.                gen_rtx (PLUS, Pmode, addr,
  419.                     gen_rtx (CONST_INT, Pmode, 4))),
  420.           scratch);
  421.           
  422.   emit_move_insn (scratch, f0_addr);
  423.   emit_move_insn (gen_rtx (MEM, SImode,
  424.                gen_rtx (PLUS, Pmode, addr,
  425.                     gen_rtx (CONST_INT, Pmode, 8))),
  426.           scratch);
  427.           
  428.   emit_move_insn (scratch, r1_addr);
  429.   emit_move_insn (gen_rtx (MEM, SImode,
  430.                gen_rtx (PLUS, Pmode, addr,
  431.                     gen_rtx (CONST_INT, Pmode, 12))),
  432.           scratch);
  433.           
  434.   emit_move_insn (scratch, f1_addr);
  435.   emit_move_insn (gen_rtx (MEM, SImode,
  436.                gen_rtx (PLUS, Pmode, addr,
  437.                     gen_rtx (CONST_INT, Pmode, 16))),
  438.           scratch);
  439.  
  440.   /* Return the address of the va_list constructor, but don't put it in a
  441.      register.  This fails when not optimizing and produces worse code when
  442.      optimizing.  */
  443.  
  444.   return XEXP (block, 0);
  445. }
  446.  
  447.  
  448. /* Return truth value of whether OP can be used as an word register
  449.    operand. Reject (SUBREG:SI (REG:SF )) */
  450.  
  451. int
  452. int_reg_operand (op, mode)
  453.      rtx op;
  454.      enum machine_mode mode;
  455. {
  456.   return (register_operand (op, mode) &&
  457.       (GET_CODE (op) != SUBREG ||
  458.        GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_INT));
  459. }
  460.  
  461. /* Return truth value of whether OP can be used as a float register
  462.    operand. Reject (SUBREG:SF (REG:SI )) )) */
  463.  
  464. int
  465. fp_reg_operand (op, mode)
  466.      rtx op;
  467.      enum machine_mode mode;
  468. {
  469.   return (register_operand (op, mode) &&
  470.       (GET_CODE (op) != SUBREG ||
  471.        GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_FLOAT));
  472. }
  473.  
  474.